package cn.ywyself.extend.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 字符串处理工具，包含一些格式的验证
 *
 * @author : ywyself
 * @created : 2018-10-20 11:38
 */
@SuppressWarnings("unused")
public class StringUtils {

    /**
     * 手机号格式检查
     */
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[0-9]\\d{4,10}$");

    /**
     * 邮箱格式检查
     */
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^\\w[-\\w.]*@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$");

    /**
     * 对qq号进行验证，要求5~15位，不能以0开头，只能是数字
     */
    private static final Pattern QQ_PATTERN = Pattern.compile("[1-9][0-9]{4,14}");

    /**
     * 姓名检查，支持少数民族的人名，或者外国人的中译名[需要考虑支持少数民族的人名，或者外国人的中译名]
     */
    private static final Pattern NAME_PATTERN = Pattern.compile("^[\\u4E00-\\u9FA5]{2,5}(?:·[\\u4E00-\\u9FA5]{2,5})*$");

    /**
     * 检查输入文本是否为手机号格式
     *
     * @param str 输入文本
     * @return true|符合手机号规则
     */
    public static boolean isPhone(String str) {
        return matchRegex(str, PHONE_PATTERN);
    }

    /**
     * 检查输入文本是否为邮箱格式
     *
     * @param str 输入文本
     * @return true|符合邮箱格式
     */
    public static boolean isEmail(String str) {
        return matchRegex(str, EMAIL_PATTERN);
    }

    /**
     * 检查输入文本是否为QQ号格式
     *
     * @param str 输入文本
     * @return true|符合QQ号格式
     */
    public static boolean isQQ(String str) {
        return matchRegex(str, QQ_PATTERN);
    }

    /**
     * 姓名检查，支持少数民族的人名，或者外国人的中译名
     *
     * @param name 字符串
     * @return true|合法姓名
     */
    public static boolean isName(String name) {
        return matchRegex(name, NAME_PATTERN);
    }

    /**
     * 检查输入文本是否为URL格式，输入文本必须以http开头，否则会返回false
     *
     * @param str 输入文本
     * @return true|符合URL格式
     */
    public static boolean isUrl(String str) {
        if (null == str || "".equals(str.trim())) {
            return false;
        }
        try {
            str = str.trim();
            if (str.startsWith("https://")) {
                str = "http://" + str.substring(8); // URL doesn't understand the https protocol, hack it
            }
            new URL(str);
            return true;
        } catch (MalformedURLException ignored) {
            return false;
        }
    }

    /**
     * 检查字符串是否符合正则表达式
     *
     * @param str     字符串
     * @param pattern 正则表达式
     * @return true|满足表达式，str为null返回false
     */
    public static boolean matchRegex(String str, Pattern pattern) {
        if (null == str) {
            return false;
        }
        Matcher matcher = pattern.matcher(str);
        return matcher.matches();
    }

    /**
     * 对字符串进行UTF-8格式URL编码
     *
     * @param str 输入字符串
     * @return 编码后的字符串
     */
    public static String urlEncode(String str) {
        return urlEncode(str, "UTF-8");
    }

    /**
     * 对字符串进行URL编码
     *
     * @param str 输入字符串
     * @param enc 编码格式
     * @return 编码后的字符串
     */
    public static String urlEncode(String str, String enc) {
        try {
            return URLEncoder.encode(str, enc);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return str;
        }
    }

    /**
     * 对字符串进行UTF-8格式URL解码
     *
     * @param text 待解码内容
     * @return 经过解码后的内容，遇到异常返回""
     */
    public static String urlDecode(String text) {
        return urlDecode(text, "UTF-8");
    }

    /**
     * 对字符串进行URL解码
     *
     * @param text 待解码内容
     * @param enc  编码格式
     * @return 经过解码后的内容，遇到异常返回""
     */
    public static String urlDecode(String text, String enc) {
        try {
            return URLDecoder.decode(text, enc);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return text;
        }
    }

    /**
     * 将json格式的字符串转换为map对象
     *
     * @param jsonStr json格式字符串
     * @return map对应json的层级，不会返回null
     */
    public static Map<String, Object> jsonToMap(String jsonStr) {
        JSONObject jsonObject;
        try {
            jsonObject = JSONArray.parseObject(jsonStr);
            if (jsonObject == null) {
                return new HashMap<>();
            }
        } catch (Exception e) {
            return new HashMap<>();
        }
        return jsonObject.getInnerMap();
    }

    /**
     * 将json展开为一层，存放在map对象中
     *
     * @param jsonStr json数据
     * @param data    存储元素的变量
     */
    public static void jsonToMap(String jsonStr, Map<String, Object> data) {
        Map<String, String> jsonMap = JSON.parseObject(jsonStr, new TypeReference<LinkedHashMap<String, String>>() {
        });
        for (Map.Entry<String, String> entry : jsonMap.entrySet()) {
            if (null == entry.getValue() || "".equals(entry.getValue().trim())) {
                data.put(entry.getKey(), entry.getValue());
            } else if (entry.getValue().indexOf("{") == 0) {
                jsonToMap(entry.getValue(), data);
            } else {
                data.put(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * 隐藏信息，替换字符串中间部分为*号，邮箱只替换@前面的字符串
     *
     * @param str 输入文本
     * @return 打码后的文本
     */
    public static String hideMiddle(String str) {
        if (null == str || "".equals(str.trim())) {
            return "";
        }
        // 如果是邮箱，则采用邮箱的隐藏方式
        if (isEmail(str)) {
            return hideEmail(str);
        }
        int length = str.length();
        // 开头保留
        int partA = length / 3;
        // 结尾保留
        int partB = (length - partA) / 2;
        // 结果
        StringBuilder sb = new StringBuilder(length);
        if (partA > 0) {
            sb.append(str, 0, partA);
        }
        for (int i = 0; i < length - partA - partB; i++) {
            sb.append("*");
        }
        if (partB > 0) {
            sb.append(str, length - partB, length);
        }
        return sb.toString();
    }

    /**
     * 隐藏手机号中间4位
     *
     * @param str 手机号码，只能为11位手机号
     */
    public static String hidePhone(String str) {
        return str.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }


    /**
     * 邮箱用****号隐藏前面的字母
     *
     * @param email 邮箱账号，只能是符合简单邮箱规则的字符串
     */
    public static String hideEmail(String email) {
        return email.replaceAll("(\\w?)(\\w+)(\\w)(@\\w+\\.[a-z]+(\\.[a-z]+)?)", "$1****$3$4");
    }

    /**
     * 身份证号用****号隐藏前面的字母
     *
     * @param idCard 身份证号，只能是18位身份证号
     */
    public static String hideID(String idCard) {
        return idCard.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1*****$2");
    }

    public static void main(String[] args) {
        System.out.println(hideMiddle("420921199309165777"));
        System.out.println(hideID("420921199309165777"));
    }
}
